using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Zune
{
    /// <summary>
    /// Base class for all ButtonWatch components.  These fire a ButtonTriggered event
    /// whenever something happens to their associated ZuneButton (button is pressed,
    /// released, etc).  
    /// </summary>
    public abstract class ButtonWatch : GameComponent
    {
        public event ButtonTriggered Triggered;

        private ZuneButtons button;
        private Zune zune;

        protected ButtonWatch(Game game, Zune zune, ZuneButtons button)
            : base(game)
        {
            this.button = button;
            if (zune == null) throw new ArgumentNullException("zune");
            this.zune = zune;
        }

        #region Properties
        /// <summary>
        /// Gets or sets the ZuneButton this object is watching.
        /// </summary>
        public ZuneButtons Button
        {
            get { return button; }
            set { button = value; }
        }
        /// <summary>
        /// Gets the Zune device this object is using to check input changes.
        /// </summary>
        public Zune Zune
        {
            get { return zune; }
        }
        #endregion
        
        public override void Update(GameTime gameTime)
        {
            if (this.IsTriggered())
                RaiseButtonEvent();
        }

        /// <summary>
        /// ButtonWatch.Update will call this function and raise the Triggered event
        /// if it returns true.
        /// </summary>
        /// <returns>True if watch conditions are met, false otherwise</returns>
        protected abstract bool IsTriggered();
        
        /// <summary>
        /// Raises the ButtonWatch.Triggered event
        /// </summary>
        protected void RaiseButtonEvent()
        {
            if (Triggered != null)
                Triggered(this, new ButtonTriggeredEventArgs(button));
        }
    }

    /// <summary>
    /// Indicates that a watched button has been triggered, according to what value
    /// IsTriggered() returns.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public delegate void ButtonTriggered(object sender, ButtonTriggeredEventArgs e);

    /// <summary>
    /// Event arguments for a ButtonTriggered event.  Includes what ZuneButton 
    /// the event was fired for.
    /// </summary>
    public class ButtonTriggeredEventArgs : EventArgs
    {
        private ZuneButtons button;

        public ButtonTriggeredEventArgs(ZuneButtons button)
        {
            this.button = button;
        }

        public ZuneButtons Button
        {
            get { return button; }
        }
    }


    /// <summary>
    /// Raises a button event whenever the associated button is newly pressed (not held).
    /// </summary>
    public class OnPressWatch : ButtonWatch
    {
        public OnPressWatch(Game game, Zune zune, ZuneButtons button)
            : base(game, zune, button)
        { }

        protected override bool IsTriggered()
        {
            return Zune.IsNewPress(Button);
        }
    }
    /// <summary>
    /// Raises a button event whenever the associated button is released from being pressed.
    /// </summary>
    public class OnReleaseWatch : ButtonWatch
    {
        bool pressedLast = false;
        public OnReleaseWatch(Game game, Zune zune, ZuneButtons button)
            : base(game, zune, button)
        { }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
            pressedLast = Zune.IsPressed(Button);
        }

        protected override bool IsTriggered()
        {
            return (pressedLast == true && Zune.IsPressed(Button) == false);
        }
    }
    /// <summary>
    /// Raises a button event every time the control updates and the associated button is pressed.
    /// </summary>
    public class AlwaysWatch : ButtonWatch
    {
        public AlwaysWatch(Game game, Zune zune, ZuneButtons button)
            : base(game, zune, button)
        { }

        protected override bool IsTriggered()
        {
            return Zune.IsPressed(Button);
        }
    }
    /// <summary>
    /// Raises a button event at fixed intervals as long as the button is held.
    /// </summary>
    public class FixedIntervalWatch : ButtonWatch
    {
        private TimeSpan watchInterval;
        private TimeSpan remainder;

        public FixedIntervalWatch(Game game, Zune zune, ZuneButtons button, TimeSpan watchInterval)
            : base(game, zune, button)
        { }
        
        /// <summary>
        /// Gets or sets the length of time between events while the button is held
        /// </summary>
        public TimeSpan WatchInterval
        {
            get { return watchInterval; }
            set { watchInterval = value; }
        }

        public override void Update(GameTime gameTime)
        {
            if (Zune.IsPressed(Button))
                remainder += gameTime.ElapsedGameTime;
            else
                remainder = TimeSpan.Zero;

            base.Update(gameTime);

            if (remainder > watchInterval)
                remainder -= watchInterval;
        }

        protected override bool IsTriggered()
        {
            if (Zune.IsNewPress(Button))
                return true;
            return (watchInterval < remainder);
        }
    }




    
}